Skip to content

Add maestro E2E test app#1635

Open
ajpallares wants to merge 36 commits intomainfrom
e2e-tests-app
Open

Add maestro E2E test app#1635
ajpallares wants to merge 36 commits intomainfrom
e2e-tests-app

Conversation

@ajpallares
Copy link
Copy Markdown
Member

@ajpallares ajpallares commented Feb 27, 2026

Summary

Adds a Maestro E2E test app under e2e-tests/MaestroTestApp/ — a minimal React Native app with two screens used by automated Maestro flows to verify the RevenueCat purchase integration.

  • Two screens: "Test Cases" list and "Purchase through paywall" (presents a RevenueCat V2 paywall and displays entitlement status)
  • Bundle ID com.revenuecat.automatedsdktests
  • API key placeholder (MAESTRO_TESTS_REVENUECAT_API_KEY) replaced at CI time via sed
  • Local SDK resolution via Yarn workspace + babel-plugin-module-resolver + Metro watchFolders (same mechanism as purchaseTesterTypescript)
  • Errors from getCustomerInfo and presentPaywall are surfaced in the UI (not just logged) for Maestro screenshot capture
  • Uses testID props for reliable Maestro element targeting
  • Typed navigation with RootStackParamList
  • Includes a README and committed Podfile.lock

Counterpart PRs: purchases-flutter#1654, purchases-capacitor#699, cordova-plugin-purchases#857, purchases-unity#836, purchases-kmp#708

Follow-up PRs (stacked)

  • #1636 — Maestro test flows (YAML)
  • #1637 — CircleCI jobs to run the tests

Co-Authored-By: Claude Opus 4.6 <[email protected]>
Generated iOS project boilerplate from React Native 0.76.0 template with
bundle ID set to com.revenuecat.maestro.e2e. Includes xcodeproj, app delegate,
launch screen, privacy manifest, asset catalog, and test target.

Co-Authored-By: Claude Opus 4.6 <[email protected]>
@ajpallares ajpallares added pr:other A code change that improves performance and removed pr:feat A new feature labels Feb 27, 2026
ajpallares and others added 12 commits February 27, 2026 12:56
The RN repo uses Yarn workspaces, so a standalone yarn.lock is needed
to prevent Yarn from treating MaestroTestApp as part of the workspace.

Co-Authored-By: Claude Opus 4.6 <[email protected]>
react-native-screens 4.24+ requires RN 0.77+ codegen.

Co-Authored-By: Claude Opus 4.6 <[email protected]>
Align with purchaseTesterTypescript patterns: ignore .yarn cache,
.xcode.env.local, Xcode artifacts, and stop over-ignoring xcworkspace.

Co-Authored-By: Claude Opus 4.6 <[email protected]>
Replace Objective-C AppDelegate (AppDelegate.h, AppDelegate.mm, main.m)
with a Swift AppDelegate using @main annotation. Also adds required
devDependencies for pod install to work correctly.

Co-Authored-By: Claude Opus 4.6 <[email protected]>
Co-Authored-By: Claude Opus 4.6 <[email protected]>
Made-with: Cursor
The StoreKitConfiguration.storekit file was on disk but not registered
as a PBXFileReference in project.pbxproj, so Xcode couldn't find it
at runtime. Also fix the scheme identifier path.

Made-with: Cursor
The identifier is relative to the .xcodeproj directory, so it needs
the ../ prefix to reach the sibling StoreKitConfiguration.storekit.

Made-with: Cursor
@RevenueCat-Danger-Bot
Copy link
Copy Markdown

RevenueCat-Danger-Bot commented Mar 30, 2026

2 Warnings
⚠️ Size check is being bypassed due to the presence of the label "danger-bypass-size-limit"
⚠️ Size increase: 258.45 KB

Generated by 🚫 Danger

- Use portal: references for react-native-purchases and
  react-native-purchases-ui so E2E tests exercise the local branch
  code instead of whatever is published on npm
- Commit ios/Podfile.lock for reproducible CI builds (force-added
  since root .gitignore has **/Podfile.lock)
- Add try/catch to presentPaywall for diagnosable test failures
- Type the navigation prop with RootStackParamList
- Add README with build/run instructions and API key setup

Made-with: Cursor
… add testID

- Add e2e-tests/MaestroTestApp to root workspaces (matching
  purchaseTesterTypescript pattern)
- Replace portal: deps with babel module-resolver aliases to SDK source
- Configure Metro watchFolders + exclusionList for out-of-root resolution
- Surface presentPaywall errors in a visible <Text testID="error-message">
  instead of only console.error, so Maestro can capture failures
- Switch from accessibilityLabel to testID for reliable Maestro targeting
- Update README to describe the workspace + module-resolver mechanism

Made-with: Cursor
…ile.lock

- Add .catch() to getCustomerInfo() to surface errors in the UI instead
  of producing an unhandled promise rejection
- Replace deprecated blacklistRE with blockList in metro.config.js
- Regenerate Podfile.lock under current workspace setup (was generated
  under the old portal: setup)

Made-with: Cursor
Without this file, CocoaPods' use_native_modules! doesn't know where
to find react-native-purchases and react-native-purchases-ui, since
they aren't explicit npm dependencies of the test app.
Mirrors the purchaseTesterTypescript example.

Made-with: Cursor
Include react-native-purchases and react-native-purchases-ui as Gradle
projects so the Android autolinker can resolve them. Mirrors the
purchaseTesterTypescript example.

Made-with: Cursor
RN 0.76.x is incompatible with react-native-purchases-ui's AGP 8.13.2
(NativeDeviceEventManagerSpec unresolved supertype during Kotlin compilation).

- React Native 0.76.9 → 0.78.0 (+ React 19, safe-area-context 5, screens 4.5)
- Gradle wrapper 8.10.2 → 8.14.4
- Kotlin 1.9.25 → 2.0.21, NDK 26 → 27, targetSdk 34 → 35
- Add allprojects repositories block and explicit Gradle project includes
- Regenerate Podfile.lock and yarn.lock

Made-with: Cursor
react-native-screens 4.24.0 has a codegen incompatibility with
RN 0.78 ("Unknown prop type for accessibilityContainerViewIsModal").
Pin to ~4.11.0 (matching purchaseTesterTypescript) and regenerate
both yarn.lock and Podfile.lock.

Made-with: Cursor
The CLI is a devDependency of react-native (not production), so it's
not installed transitively. Both pod install (use_native_modules!) and
Gradle autolinking (RNGP) require it to discover native modules.

Made-with: Cursor
Resolve yarn.lock conflict by regenerating.

Made-with: Cursor
@ajpallares ajpallares marked this pull request as ready for review April 3, 2026 16:39
@ajpallares ajpallares requested a review from a team as a code owner April 3, 2026 16:39
@ajpallares ajpallares added the danger-bypass-size-limit Apply this label to bypass Dangerbot's size limit. label Apr 6, 2026
- Add ReactAppDependencyProvider for RN 0.78+ native component registration
- Always use pre-bundled JS instead of Metro dev server (CI has no Metro)
- Force JS bundling in Android debug builds by setting debuggableVariants = []

Made-with: Cursor
- Replace force-unwrap in bundleURL() with guard + fatalError for a
  more debuggable crash when main.jsbundle is missing
- Add comment in babel.config.js explaining how SDK packages are
  resolved from repo source without being in package.json dependencies

Made-with: Cursor
The committed Podfile.lock goes stale when yarn resolves a different
react-native patch (hermes-engine version changes). Since this is a
CI-only test app rebuilt from scratch every run, not committing the
lockfile avoids the staleness problem.

Made-with: Cursor
Reverting the previous decision to gitignore Podfile.lock. Instead,
we'll enforce immutable yarn installs on CI (no YARN_ENABLE_IMMUTABLE_INSTALLS=false)
so versions don't drift, and the committed Podfile.lock stays consistent
with yarn.lock.

Made-with: Cursor
MaestroTestApp is a workspace of the root package.json, so the root
yarn.lock is the source of truth. The local yarn.lock was an artifact
from project initialization and was pinning [email protected] while
the root lockfile pins 0.78.0, causing immutable install failures on CI.

Made-with: Cursor
react-native 0.78.0 ships a fmt version with consteval C++20 errors
when compiled with Xcode 26.4's clang. Pinning to 0.78.3 which
includes the fix. Updated yarn.lock and Podfile.lock accordingly.

Made-with: Cursor
react-native 0.78.0 ships an fmt version with consteval C++20
compilation errors on Xcode 26.4's clang. Bumping all workspaces to
0.78.3 (patch update) which includes the fix. This also keeps a single
react-native version across workspaces, ensuring proper Yarn hoisting
of shared dependencies like @react-native/babel-preset.

Reverts the MaestroTestApp exact pin to ^0.78.0 (range) since the
lockfile now resolves all ^0.78.0 ranges to 0.78.3.

Made-with: Cursor
Reverting the attempt to commit Podfile.lock and bump react-native
to 0.78.3. The react-native version update is out of scope for the
Maestro e2e test setup.

Instead, Podfile.lock remains gitignored and will be generated fresh
on each CI run using YARN_ENABLE_IMMUTABLE_INSTALLS=false (in PR3)
to let yarn resolve the latest compatible react-native patch.

Made-with: Cursor
@ajpallares ajpallares changed the title feat: add maestro E2E test app Add maestro E2E test app Apr 6, 2026
Copy link
Copy Markdown
Contributor

@tonidero tonidero left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just some thoughts, but nothing really blocking. Amazing job!!

/**
* Set this to true to Run Proguard on Release builds to minify the Java bytecode.
*/
def enableProguardInReleaseBuilds = false
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just curious, was this the default? If not, I wonder if we should enable it, so we can have more proper tests that actually minify the app

@@ -0,0 +1,37 @@
# Resolve react_native_pods.rb with node to allow for hoisting
require Pod::Executable.execute_command('node', ['-p',
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just to check, we still need to have a Podfile here right? As in, we can't use just SPM already for this new project?

"@react-navigation/native": "^7.0.0",
"@react-navigation/native-stack": "^7.0.0",
"react": "19.0.0",
"react-native": "^0.78.0",
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I do wonder if we should have done these tests directly with an Expo app... But I think it's fine to keep it to plain react native for now 👍

"examples/purchaseTesterTypescript",
"react-native-purchases-ui"
"react-native-purchases-ui",
"e2e-tests/MaestroTestApp"
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Not related to this line]
Should we add a command to update the pods for the new app in the boostrap command above?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

danger-bypass-size-limit Apply this label to bypass Dangerbot's size limit. pr:other A code change that improves performance

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants